/* Kanvas Paint and Drawing Tool.
 * Copyright (C) 2011 Darryl Wallace
 * wallacdj@gmail.com / darryl@wallynet.ca
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*!
  @file Canvas.cpp
  @author Darryl Wallace
  @date 2011
  @brief This file implements the Canvas class.
  */

#include "Canvas.h"
#include "LayerItem.h"
#include "../PluginInterface/ITool.h"
#include "AnchorHandle.h"

Canvas::Canvas(int w, int h, QObject *parent)
    : QGraphicsScene(parent),
      _backgroundLayer(NULL),
      _pixelGrid(NULL),
      _currentLayer(NULL),
      _currentLayerIndex(-1),
      _primaryColor("#000000"),
      _secondaryColor("#FFFFFF"),
      _currentTool(NULL),
      _activeTool(NULL),
      _currentZoomFactor(1.0)
{
    // draw background pixmap.
    int gridSize=10;
    QPixmap backgroundPixmap(gridSize*2, gridSize*2);
    backgroundPixmap.fill(QColor(Qt::white));
    QPainter painter(&backgroundPixmap);
    QColor backgroundColor(Qt::gray);
    painter.fillRect(0,0,gridSize,gridSize,backgroundColor);
    painter.fillRect(gridSize,gridSize,gridSize,gridSize, backgroundColor);

    painter.end();

    QPen p(Qt::black);
    p.setWidth(1);
    p.setJoinStyle(Qt::MiterJoin);

    _backgroundLayer = addRect(0,0, w, h, p, QBrush(backgroundPixmap));
    _backgroundLayer->setZValue(0);
}

bool Canvas::addLayer()
{
    LayerItem *layer=new LayerItem(_backgroundLayer);
    _currentLayer=layer;
    _layers.append(layer);
    layer->setZValue(_layers.size()*10);
    _currentLayerIndex=_layers.size()-1;
    return true;
}

bool Canvas::deleteLayer(int index)
{
    if (index>=_layers.size())
        return false;
    LayerItem *layer = _layers.takeAt(index);
    if (!layer)
        return false;
    removeItem(layer);
    delete layer;
    return true;
}

bool Canvas::setCurrentLayer(int index)
{
    if (index>=_layers.size())
        return false;
    _currentLayer=_layers.at(index);
    if (_currentTool)
        _currentTool->setLayerItem(_currentLayer);
    return true;
}

LayerItem * Canvas::getLayer(int index)
{
    if (index>=_layers.size())
        return NULL;
    return _layers.at(index);
}

int Canvas::getCurrentLayerIndex() const
{
    return _currentLayerIndex;
}

void Canvas::moveLayerUp(int index)
{
    if (index==_layers.size()-1)
        return;
    LayerItem *layer = _layers.takeAt(index);

    _layers.insert(index+1, layer);
    // reset all of the z-orders.
    for(int i=0; i<_layers.size();i++)
    {
        _layers.at(i)->setZValue(10*(i+1));
    }
    invalidate();
}

void Canvas::moveLayerDown(int index)
{
    if (index==0)
        return;
    LayerItem *layer = _layers.takeAt(index);
    _layers.insert(index-1,layer);
    // reset all of the z-orders.
    for(int i=0; i<_layers.size();i++)
    {
        _layers.at(i)->setZValue(10*(i+1));
    }
    invalidate();
}

void Canvas::setPrimaryColor(const QColor &p)
{
    _primaryColor=p;
    if (_currentTool)
        _currentTool->setPrimaryColor(_primaryColor);
}

void Canvas::setSecondaryColor(const QColor &s)
{
    _secondaryColor=s;
    if (_currentTool)
        _currentTool->setSecondaryColor(_secondaryColor);
}

void Canvas::setCurrentTool(ITool *tool)
{
    if (_currentTool)
        disconnect(_currentTool,0,this,0);
    _currentTool=tool;

    _currentTool->setPrimaryColor(_primaryColor);
    _currentTool->setSecondaryColor(_secondaryColor);
    connect(_currentTool, SIGNAL(statusMessage(const QString &)),
            this, SIGNAL(statusMessage(const QString &)));
    applyTransformToTool();
}

void Canvas::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
{
    return;
}

void Canvas::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (_activeTool)
    {
        // check each anchor to see if the click landed within it's boundingRect()
        foreach(QGraphicsItem *g, _activeTool->anchorHandles())
        {
            if (g->boundingRect().contains(event->scenePos()))
            {
                qDebug()<<"Clicked handle"<<g->boundingRect()<<event->scenePos();
                QGraphicsScene::mousePressEvent(event);
                return;
            }
            else
            {
                qDebug()<<"missed handle"<<g->boundingRect()<<event->scenePos();
                g->setVisible(false);
            }
        }

        removeItem(_activeTool);
        _activeTool=NULL;
        update();
    }
    else if (_currentTool)
    {
        _activeTool=_currentTool;
        _activeTool->setLayerItem(_currentLayer);
        _activeTool->handleMousePressEvent(event);
        if (_currentZoomFactor==1.0)
            _activeTool->setCacheMode(QGraphicsItem::NoCache);
        else
            _activeTool->setCacheMode(QGraphicsItem::ItemCoordinateCache);  // thanks steve
        if (_activeTool->updateMode()==ITool::EntireCanvas)
            update();
        else if(_activeTool->updateMode()==ITool::BoundingRect)
            _activeTool->update();

    }
}

void Canvas::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{

    if (_activeTool)
    {
        _activeTool->handleMouseMoveEvent(event);
        if (_activeTool->updateMode()==ITool::EntireCanvas)
            update();
        else if(_activeTool->updateMode()==ITool::BoundingRect)
            _activeTool->update();
    }
}

void Canvas::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsScene::mouseReleaseEvent(event);
    if (_activeTool)
    {
        _activeTool->handleMouseReleaseEvent(event);
        _currentLayer->addItem(_activeTool);
        if (_activeTool->updateMode()==ITool::EntireCanvas)
            update();
        else if(_activeTool->updateMode()==ITool::BoundingRect)
            _activeTool->update();
        if (_activeTool->isPersistent())
        {
            foreach (QGraphicsItem * anchor, _activeTool->anchorHandles())
            {
                anchor->setVisible(true);
            }
        }
        else
        {
            removeItem(_activeTool);
            _activeTool=NULL;
        }
    }
}

void Canvas::save(const QString & filename, FileSaveTypes type)
{
    QImage image;
    switch(type)
    {
    case PNG:
        break;
    default:
        break;
    }
}

void Canvas::resize(int width, int height, ResizeAnchor anchorLocation)
{
    _backgroundLayer->setRect(0,0,width,height);
    foreach (LayerItem *layer, _layers)
    {
        layer->resize(width,height,anchorLocation);
    }
}

void Canvas::scaleImage(qreal sx, qreal sy)
{
    QRectF rect=_backgroundLayer->rect();
    qreal newWidth=rect.width()*sx;
    qreal newHeight=rect.height()*sy;

    _backgroundLayer->setRect(0,0,newWidth,newHeight);
    foreach (LayerItem *layer, _layers)
    {
        layer->scaleImage(sx, sy);
    }
    invalidate();
}

void Canvas::enablePixelGrid(bool on)
{
    _pixelGrid->setVisible(on);
}

void Canvas::setLayerVisible(int index, bool visible)
{
    if (index>=_layers.size())
        return;
    _layers.at(index)->setVisible(visible);
}

QSize Canvas::canvasSize() const
{
    QRectF r=_backgroundLayer->rect();
    return QSize((int)r.width(), (int)r.height());
}

void Canvas::setCurrentZoomFactor(qreal zoomfactor)
{
    _currentZoomFactor=zoomfactor;
    applyTransformToTool();
}

void Canvas::applyTransformToTool()
{
    //pen.setWidthF(5./qAbs(painter->deviceTransform().m12()));
    //_currentTool->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
}




